<?php

namespace App\Services\Utils;

use App\Services\AliYun\OSS;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Str;

trait OSSable
{
    protected $default_key_prefix = 'misc/';

    /**
     * @param UploadedFile $file
     * @param string $key_prefix
     * @param bool $hash_key
     * @param string $custom_ext
     *
     * @return string
     * @throws \Exception
     */
    public function uploadPostFile(UploadedFile $file, $key_prefix = '', $hash_key = true, $custom_ext = '')
    {
        $file_origin_name = $file->getClientOriginalName();
        $dir_name = $this->normalizeOSSDirName($key_prefix);

        if ($hash_key) {
            $time_stamp = date('_Y_m_d');
            $ext = $custom_ext ?: last(explode(".", $file_origin_name));
            $hash = md5($file_origin_name . time());
            $object_key = $dir_name . $hash . $time_stamp . '.' . $ext;
        } else {
            $object_key = $dir_name . $file_origin_name;
        }

        OSS::getClient()->putObject(
            OSS::projectBucket(),
            $object_key,
            $file->getRealPath()
        );

        return $object_key;
    }

    /**
     *  保存指定名称
     *
     * @param UploadedFile $file
     * @param string $object_key_prefix
     * @param $file_name
     *
     * @return string
     * @throws \Exception
     */
    public function uploadPostFileWithName(UploadedFile $file, $object_key_prefix = '', $file_name)
    {
        $dir_name = $this->normalizeOSSDirName($object_key_prefix);

        $key = $dir_name . $file_name;

        OSS::getClient()->putObject(OSS::projectBucket(), $key, $file->getRealPath());

        return $key;
    }


    /**
     * @param string $file_path
     * @param string $key_prefix
     * @param bool $hash_key
     *
     * @return string
     * @throws \OSS\Core\OssException
     */
    public function uploadFile($file_path, $key_prefix = '', $hash_key = true)
    {
        $prefix = $this->normalizeOSSDirName($key_prefix);

        if ($hash_key) {
            $time_stamp = '_' . date('Y_m_d');
            $ext = pathinfo($file_path, PATHINFO_EXTENSION);
            $hash = md5($file_path . time());
            $key = $prefix . $hash . $time_stamp . '.' . $ext;
        } else {
            $delimiter = PHP_OS == 'WINNT' ? '\\' : '/';
            $path_arr = explode( $delimiter , $file_path );  // win环境用“\\”，linux环境下用"/"
            $key = $prefix . last($path_arr);
        }

        OSS::getClient()->putObject(OSS::projectBucket(), $key, $file_path);

        return $key;
    }

    /**
     * @param $key
     *
     * @return string
     * @throws \OSS\Core\OssException
     */
    public function getStaticUrl($key)
    {
        return head(explode('?', $this->getOSSUrl($key)));
    }

    /**
     * @param $dir_name
     * @return string
     */
    private function normalizeOSSDirName($dir_name = null)
    {
        return $dir_name
            ? $this->padStringEnding($dir_name, '/')
            : $this->default_key_prefix;
    }


    /**
     * 如果字符串结尾没有以 ending 结尾，刚补上 ending
     *
     * @param string $str
     * @param string $ending
     * @return string
     */
    private function padStringEnding($str, $ending)
    {
        return Str::endsWith($str, $ending)
            ? $str
            : $str . $ending;
    }

    /**
     * @param $objKey
     *
     * @return mixed
     * @throws \OSS\Core\OssException
     */
    public function getOSSUrl($objKey)
    {
        if (is_int(strpos($objKey,'http'))) return $objKey;

        return OSS::getClient()->getObject(
            OSS::projectBucket(),
            $objKey
        );
    }

    /**
     * Delete
     */

    /**
     * @param array $column_names
     * @throws \Exception
     */
    public function deleteOSSColumns(array $column_names)
    {
        if (! is_array($column_names)) {
            throw new \Exception('column_names need to be an array');
        }

        array_map([$this, 'deleteOSSColumn'], $column_names);
    }
    /**
     * @param array $column_names
     * @throws \Exception
     */
    public function deleteOSSJsonColumns(array $column_names)
    {
        if (! is_array($column_names)) {
            throw new \Exception('column_names need to be an array');
        }

        array_map([$this, 'deleteOSSJsonArr'], $column_names);
    }
    /**
     * @param string $column_name
     * @return bool|null|string
     * @throws \Exception
     */
    public function deleteOSSColumn($column_name)
    {
        if (! $column_name || ! is_string($column_name)) {
            throw new \Exception('column_name need to be an column name');
        }

        if (! isset($this->attributes) || ! $this->attributes[$column_name]) return null;

        return $this->deleteOSSKey($this->attributes[$column_name]);
    }
    /**
     * @param $key
     * @return bool
     */
    public function deleteOSSKey($key)
    {
        if (! $this->isOSSKeyValidated($key)) return false;

        try {
            OSS::getClient()->deleteObject(OSS::projectBucket(), $key);
        } catch (\Exception $e) {
            logger("[OSS ERROR] OSS key: {$key} delete error: {$e->getMessage()}");
            return false;
        }

        return true;
    }
    /**
     * @param $column_name
     * @return bool|null
     * @throws \Exception
     */
    public function deleteOSSJsonArr($column_name)
    {
        if (! $column_name || ! is_string($column_name)) {
            throw new \Exception('column_name need to be an column name');
        }

        if (! isset($this->attributes) || ! $this->attributes[$column_name]) return null;

        $key_arr = json_decode($this->attributes[$column_name]);

        if (! is_array($key_arr) || ! count($key_arr)) {
            return false;
        } else {
            array_map([$this, 'deleteOSSKey'], $key_arr);

            return true;
        }
    }
    /**
     * @param mixed $key
     * @return bool
     */
    private function isOSSKeyValidated($key)
    {
        return $key && is_string($key) && mb_strpos($key, 'http') !== 0;
    }

    /**
     * Migration Deprecated
     */

    /**
     * @deprecated
     *
     * @param string $bos_key
     *
     * @return string
     * @throws \OSS\Core\OssException
     */
    public function getBosUrl($bos_key)
    {
        return $this->getOSSUrl($bos_key);
    }
    /**
     * @deprecated
     *
     * @param array $column_names
     * @throws \Exception
     */
    public function deleteBosColumns(array $column_names)
    {
        $this->deleteOSSColumns($column_names);
    }
    /**
     * @deprecated
     *
     * @param array $column_names
     * @throws \Exception
     */
    public function deleteBosJsonColumns(array $column_names)
    {
        if (! is_array($column_names)) {
            throw new \Exception('column_names need to be an array');
        }

        array_map([$this, 'deleteBosJsonArr'], $column_names);
    }
    /**
     * @deprecated
     *
     * @param string $column_name
     * @return bool|null|string
     * @throws \Exception
     */
    public function deleteBosColumn($column_name)
    {
        return $this->deleteOSSColumn($column_name);
    }

    /**
     * @deprecated
     *
     * @param $key
     *
     * @return bool
     */
    public function deleteBosKey($key)
    {
        return $this->deleteOSSKey($key);
    }

    /**
     * @deprecated
     *
     * @param $column_name
     * @return bool|null
     * @throws \Exception
     */
    public function deleteBosJsonArr($column_name)
    {
        return $this->deleteOSSJsonArr($column_name);
    }
}
